/*
*
* FILENAME:		linear_seq.c/linear_seq.h 
* CREATED AT:		2012/May/5
* DECRITION:		implement the linear in the sequence way
* 
* MODULE:		linead list
* PLATFORM:		ubuntu-12.04/gcc-4.6.3
* AUTHOR:		incarnation-lee
* 
* ----------------------REVISION HISTROY------------------------
* No.	Date	Revised by	Function			Descrition
* 1	12/5/7	incar-lee	linear_seq_demo			implement the sequence linear list
* 2	12/5/8	incar-lee	init_lseq & destory_lseq	implement the feature of function
* 3	12/5/9	incar-lee	isEmpty_lseq,len_lseq,		implement the feature
*				add_lseq & get_lseq	
* 4	12/5/10	incar-lee	next_lseq, prior_lseq,
				insert and delete		implement the feature
  5	12/6/3	incar-lee	all				revise for error handling
*/


/* Standard C */
#include <stdio.h>
#include <stddef.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>
#include <errno.h>

/* linux related */
#include <unistd.h>
#include <fcntl.h>
#include <sys/types.h>

/* user defined */
#include "externals.h"
#include "udgtd.h"
#include "linear_seq.h"
#include "errcode.h"


S_element *sq_ele = NULL;


/**************************************
* operation functions on data element *
***************************************/

/*
* initilize the linear seq list 
*/
static STATUS init_lseq(S_sqlinear* lseq_p)
{
	assert(NULL!=lseq_p);

	gmalloc((void**)&sq_ele,sizeof(S_element)*LINEAR_SEQ_SIZE);
	memset(sq_ele,0,sizeof(S_element)*LINEAR_SEQ_SIZE);
	if(__builtin_expect(!!(NULL==sq_ele),0))
	{
		set_errcode(MEMORYNA);
		return -1;
	}
	lseq_p->elem = sq_ele;			/* init the operate structure */
	lseq_p->length = LINEAR_SEQ_SIZE;	/* the length of linear list sequenece implement */
	lseq_p->rest = LINEAR_SEQ_SIZE;		/* init the rest size of linear sequence list */
	return 0;
}	


/* 
* destroy the linear
*/
static STATUS destory_lseq(S_sqlinear* lseq_p)
{
	assert(NULL!=lseq_p);

	if(NULL!=lseq_p->elem)			/* sequence linear list exit */	
	{
		free(sq_ele);
		lseq_p->elem = NULL;
		lseq_p->length = 0;
		lseq_p->rest = 0;
		return 0;
	}
	set_errcode(NoEXIT);
	return -1;
}


/*
* clear all the element of linear list
*/
static STATUS clear_lseq(S_sqlinear* lseq_p)
{
	assert(NULL!=lseq_p);

	if(NULL!=lseq_p->elem)			/* sequence linear list exit */	
	{
		memset(lseq_p->elem,0,sizeof(S_element)*lseq_p->length);
		lseq_p->rest = lseq_p->length;
		return 0;
	}
	set_errcode(NoEXIT);
	return -1;
}


/* 
* linear list is empty 
*/
static STATUS isEmpty_lseq(S_sqlinear* lseq_p)
{
	assert(NULL!=lseq_p);

	if(NULL!=lseq_p->elem)			/* sequence linear list exit */	
		if(lseq_p->length==lseq_p->rest)
			return 0;
		return 1;
	set_errcode(NoEXIT);
	return -1;
}


/*
* the length of element exit at linear list
*/
static size_t len_lseq(S_sqlinear* lseq_p)
{
	assert(NULL!=lseq_p);

	if(NULL!=lseq_p->elem)  		/* sequence linear list exit */	
		return lseq_p->length - lseq_p->rest;
	set_errcode(NoEXIT);
	return -1;
}


/*
* append a new element at the end of linear list
*/	
static STATUS add_lseq(S_sqlinear* lseq_p,S_element* element)
{
	assert(NULL!=element);
	assert(NULL!=lseq_p);
		
	if(lseq_p->rest<=0)
	{
		set_errcode(NMSPACE);
		return -1;
	}
	memcpy(
		lseq_p->elem+len_lseq(lseq_p),
		element,
		sizeof(S_element)
	);
	lseq_p->rest--;
	return 0;
}

/*
* get the element of index in linear list
*/	
static S_element* get_lseq(S_sqlinear* lseq_p,int index)	
{
	assert(NULL!=lseq_p);

	if(NULL!=lseq_p->elem)			/* sequence linear list exit */	
	{
		if(index>=0 && index<len_lseq(lseq_p))
			return lseq_p->elem+index;
		set_errcode(INVALIDINDEX);
		return NULL;
	}
	set_errcode(NoEXIT);
	return NULL;
}

/*
* the next element 
*/
static S_element* next_lseq(S_sqlinear* lseq_p,int index)
{
	assert(NULL!=lseq_p);
	
	if(NULL!=lseq_p->elem)			/* sequence linear list exit */	
	{
		if(index>=0 && index <len_lseq(lseq_p)-1)
			return lseq_p->elem+(++index);	/* here you can write like this lseq_p->elem+++index, but do not make any confused risk */
		set_errcode(INVALIDINDEX);
		return NULL;
	}
	set_errcode(NoEXIT);
	return NULL;
}

/*
* the prior element 
*/
static S_element* prior_lseq(S_sqlinear* lseq_p,int index)
{
	assert(NULL!=lseq_p);
	
	if(NULL!=lseq_p->elem)			/* sequence linear list exit */	
	{
		if(index>0 && index <len_lseq(lseq_p))
			return lseq_p->elem+--index;	
		set_errcode(INVALIDINDEX);
		return NULL;
	}
	set_errcode(NoEXIT);
	return NULL;
}

/* 
* insert a data element 
*/
static STATUS insert_lseq(S_sqlinear* lseq_p,S_element* element,int index)
{
	S_element *elem_tmp = NULL;
	size_t len_tmp = 0;
	assert(NULL!=lseq_p);
	assert(NULL!=element);

	len_tmp = (len_lseq(lseq_p) - index)*sizeof(S_element);
	if(NULL!=lseq_p->elem)			/* linear list exit */
	{
		if(index>=0 && index<len_lseq(lseq_p))
		{
			gmalloc((void**)&elem_tmp,len_tmp);
			memcpy(elem_tmp,lseq_p->elem+index,len_tmp);		/* copy the element to temp buffer */
			memcpy(lseq_p->elem+index,element,sizeof(S_element));	/* insert the new element */
			memcpy(lseq_p->elem+(++index),elem_tmp,len_tmp);	/* copy the pre store element back to linear in new index*/
			lseq_p->rest--;
			free(elem_tmp);
			return 0;
		}		
		set_errcode(INVALIDINDEX);
		return -1;
	}
	set_errcode(NoEXIT);
	return -1;	
}


/* 
* delete a data element 
*/
static STATUS delete_lseq(S_sqlinear* lseq_p,int index)
{
	S_element *elem_tmp = NULL;
	size_t len_tmp = 0;
	assert(NULL!=lseq_p);

	len_tmp = (len_lseq(lseq_p) - index - 1)*sizeof(S_element);
	if(NULL!=lseq_p->elem)			/* linear list exit */
	{
		if(index>=0 && index<len_lseq(lseq_p))
		{
			gmalloc((void**)&elem_tmp,len_tmp);
			memcpy(elem_tmp,lseq_p->elem+index+1,len_tmp);		/* copy the element after index to temp */
			memcpy(lseq_p->elem+index,elem_tmp,len_tmp);		/* shift left the element after index */
			lseq_p->rest++;						/* update the rest */
			memset(lseq_p->elem+len_lseq(lseq_p),0,sizeof(S_element));	/* reset the last null elemnt */
			free(elem_tmp);
			return 0;
		}		
		set_errcode(INVALIDINDEX);
		return -1;
	}
	set_errcode(NoEXIT);
	return -1;	
}
